package com.wangji92.arthas.plugin.demo.service.impl;

import cn.hutool.core.thread.ThreadUtil;
import org.apache.tomcat.util.log.SystemLogHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * -Xms：java Heap初始大小， 默认是物理内存的1/64。
 * -Xmx：java Heap最大值，不可超过物理内存。
 * -Xmn：young generation的heap大小，一般设置为Xmx的3、4分之一 。增大年轻代后，将会减小年老代大小，可以根据监控合理设置。
 * -Xss：每个线程的Stack大小，而最佳值应该是128K,默认值好像是512k。
 * -XX:PermSize：设定内存的永久保存区初始大小，缺省值为64M。
 * -XX:MaxPermSize：设定内存的永久保存区最大大小，缺省值为64M。
 * -XX:SurvivorRatio：Eden区与Survivor区的大小比值，设置为8，则两个Survivor区与一个Eden区的比值为2:8，一个Survivor区占整个年轻代的1/10。
 * -XX:+UseParallelGC：F年轻代使用并发收集，而年老代仍旧使用串行收集。
 * -XX:+UseParNewGC：设置年轻代为并行收集，JDK5.0以上，JVM会根据系统配置自行设置，所无需再设置此值。
 * -XX:ParallelGCThreads：并行收集器的线程数，值最好配置与处理器数目相等 同样适用于CMS。
 * -XX:+UseParallelOldGC：年老代垃圾收集方式为并行收集(Parallel Compacting)。
 * -XX:MaxGCPauseMillis：每次年轻代垃圾回收的最长时间(最大暂停时间)，如果无法满足此时间，JVM会自动调整年轻代大小，以满足此值。
 * -XX:+ScavengeBeforeFullGC：Full GC前调用YGC,默认是true。
 * 实例如：JAVA_OPTS=”-Xms4g -Xmx4g -Xmn1024m -XX:PermSize=320M -XX:MaxPermSize=320m -XX:SurvivorRatio=6″
 * </p>
 *
 * @author liuxiongkang
 */
@Component
public class BugsService {
    private static final Logger LOG = LoggerFactory.getLogger(BugsService.class);
    /** static 和 非static 堆文件有区别 */
    private static final List<BugObject> list = new ArrayList<>();
    private static final List<BugObject> list2 = new ArrayList<>();
    private final ThreadFactory threadFactory = ThreadUtil.newNamedThreadFactory("hutool-deadlock-", false);
    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 3, 3000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory);
    private final ThreadFactory threadFactory2 = ThreadUtil.newNamedThreadFactory("hutool-cpu-", false);
    private final ThreadPoolExecutor executor2 = new ThreadPoolExecutor(30, 30, 3000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory2);

    /**
     * 内存溢出
     * -Xms -Xms设置初始堆内存的大小   -Xmx -Xmx设置最大堆内存的大小    -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\heap-dump\   -XX:-UseGCOverheadLimit 取消 GC 开销限制
     * -verbose:gc -Xms10M -Xmx10M -Xmn5M   -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:\dump.hprof
     */
    public void bug1() {
        test2();
        // test1();
    }

    private void test1() {
        int i = 0;
        try {
            while (list.size() < Integer.MAX_VALUE) {
                //1024*1024正好 1M
                Byte[] array = new Byte[1024 * 1024];
                //方便 分析数据
                array[0] = 'a';
                array[1] = 'b';
                array[2] = 'c';
                list.add(new BugObject(array));
                i++;
            }
        } catch (Exception e) {
            LOG.error("执行了{}次", i, e);
        }
        LOG.info("size:{}", list.size());
    }

    private void test2() {
        int i = 0;
        try {
            int size = 100;
            for (int i1 = 0; i1 < size; i1++) {
                //1024*1024正好 1M
                Byte[] array = new Byte[2];
                //方便 分析数据
                array[0] = 'a';
                array[1] = 'b';
                list2.add(new BugObject(array));
                i++;
            }
        } catch (Exception e) {
            LOG.error("执行了{}次", i, e);
        }
        LOG.info("size:{}", list2.size());
    }


    /**
     * 死锁
     */
    public void bug2() {
        executor.submit(() -> {
            LOG.info("lock 1 {}-{}", Thread.currentThread().getName(), Thread.currentThread().getId());
            synchronized (BugsService.class) {
                while (true) {
                    //
                    ThreadUtil.sleep(3000);
                }
            }
        });
        executor.submit(() -> {
            LOG.info("lock 2 {}-{}", Thread.currentThread().getName(), Thread.currentThread().getId());
            ThreadUtil.sleep(6000);
            synchronized (BugsService.class) {
                while (true) {
                    //
                }
            }
        });
        System.setOut(new SystemLogHandler(System.out));
        System.setErr(new SystemLogHandler(System.err));
    }

    /**
     * cpu 耗尽死循环
     */
    public void bug3() {
        for (int i = 0; i < 100; i++) {
            executor2.submit(() -> {
                while (true) {
                    LOG.info("lock cpu {}-{}", Thread.currentThread().getName(), Thread.currentThread().getId());
                }
            });
        }
    }

    static class BugObject {
        public Byte[] array;

        public BugObject(Byte[] array) {
            this.array = array;
        }
    }
}
